﻿# define _CRT_SECURE_NO_WARNINGS 1
//第21讲：自定义类型联合和枚举
//1.1 联合体类型的声明
//像结构体⼀样，联合体也是由⼀个或者多个成员构成，这些成员可以是不同的类型。联合体的关键字
//是union.
//但是编译器只为最⼤的成员分配⾜够的内存空间。联合体的特点是所有成员共⽤同⼀块内存空间。所
//以联合体也叫：共⽤体。
//给联合体其中⼀个成员赋值，其他成员的值也跟着变化。
//联合体的声明
//#include <stdio.h>
//union un
//{
//	char i;
//	int a;
//};
//int main()
//{
//	union un n = { 0 };
//	printf("%zu", sizeof(union un));
//	return 0;
//
//}
//输出结果：4
//1.2 联合体的特点
//联合的成员是共⽤同⼀块内存空间的，这样⼀个联合变量的⼤⼩，⾄少是最⼤成员的⼤⼩（因为联合
//⾄少得有能⼒保存最⼤的那个成员）
#include <stdio.h>
//union un
//{
//	char i;
//	int a;
//	double b;
//};
//int main()
//{
//	union un n = { 0 };
//	printf("%p\n",&(n.i) );
//	printf("%p\n", &(n.a));
//	printf("%p\n", &(n.b));
//	return 0;
//	/*0000005A103EFC08
//	0000005A103EFC08
//	0000005A103EFC08*/
//	//地址是一样的
//}
//#include <stdio.h>
//union un
//{
//	char i;
//	int a;
//	//double b;
//};
//int main()
//{
//	union un n = { 0 };
//	n.a = 0x11223344;
//	n.i = 0x55;
//	printf("%x", n.a);
//	//输出结果：11223355
//	return 0;
//}
//代码1输出的三个地址⼀模⼀样，代码2的输出，我们发现将i的第4个字节的内容修改为55了。
//我们仔细分析就可以画出，un的内存布局图。
//1.4 联合体⼤⼩的计算
//• 联合的⼤⼩⾄少是最⼤成员的⼤⼩。
//• 当最⼤成员⼤⼩不是最⼤对⻬数的整数倍的时候，就要对⻬到最⼤对⻬数的整数倍
//#include <stdio.h>
//union Un1
//{
//	//数组的大小是元素的大小        对齐数  默认对齐数   对齐数
//	char c[5]; //5元素的大小           1           8          1      
//	int i;     //4                    4           8           4
//	//最大成员大小是5，不是最⼤对⻬数的整数倍，就要对⻬到最⼤对⻬数4的整数倍8
//};
//union Un2
//{             
//	short c[7]; // 14                 2          8            2 
//	int i;      // 4                  4          8             4
//	//最大成员大小是14，不是最⼤对⻬数的整数倍，就要对⻬到最⼤对⻬数4的整数倍16
//};
//int main()
//{
//	//下⾯输出的结果是什么？ 
//	printf("%d\n", sizeof(union Un1));//8
//	printf("%d\n", sizeof(union Un2));//16
//	return 0;
//}
////输出结果：
//使⽤联合体是可以节省空间的，举例：
//⽐如，我们要搞⼀个活动，要上线⼀个礼品兑换单，礼品兑换单中有三种商品：图书、杯⼦、衬衫。
//每⼀种商品都有：库存量、价格、商品类型和商品类型相关的其他信息。
//图书：书名、作者、⻚数
//杯⼦：设计
//衬衫：设计、可选颜⾊、可选尺⼨
//那我们不耐⼼思考，直接写出⼀下结构：
//struct gift_list
//{
//	//公共属性 
//	int stock_number;//库存量 
//	double price; //定价 
//	int item_type;//商品类型 
//
//	//特殊属性 
//	char title[20];//书名 
//	char author[20];//作者 
//	int num_pages;//⻚数 
//
//	char design[30];//设计 
//	int colors;//颜⾊ 
//	int sizes;//尺⼨ 
//};
//上述的结构其实设计的很简单，⽤起来也⽅便，但是结构的设计中包含了所有礼品的各种属性，这样
//使得结构体的⼤⼩就会偏⼤，⽐较浪费内存。因为对于礼品兑换单中的商品来说，只有部分属性信息
//是常⽤的。⽐如：
//商品是图书，就不需要design、colors、sizes。
//所以我们就可以把公共属性单独写出来，剩余属于各种商品本⾝的属性使⽤联合体起来，这样就可以
//介绍所需的内存空间，⼀定程度上节省了内存。
//struct gift_list
//{
//	int stock_number;//库存量 
//	double price; //定价 
//	int item_type;//商品类型 
//
//	union {
//		struct
//		{
//			char title[20];//书名 
//			char author[20];//作者 
//			int num_pages;//⻚数 
//		}book;
//		struct
//		{
//			char design[30];//设计 
//		}mug;
//		struct
//		{
//			char design[30];//设计 
//			int colors;//颜⾊ 
//			int sizes;//尺⼨ 
//		}shirt;
//	}item;
//};
//判断当前机器是大端还是小端
//int check_sys()
//{
//	int i = 1;
//	//00 00 00 01  or 01 00 00 00有这两种存储可能
//	int c = *(char*)&i;
//	if (c == 1)
//		return 1;
//	else
//		return 0;
//}
//int main()
//{
//	if (check_sys() == 1)
//		printf("小端");//小端：低位低地址，高位高地址
//	else
//	{
//		printf("大端");//大端:低位高地址，高位低地址
//	}
//		return 0;
//}
//int check_sys()
//{
//	union un
//	{
//		int i;
//		char b;
//	}n;
//	n.i = 1;
//	return n.b;
//}
//int main()
//{
//	if (check_sys() == 1)
//		printf("小端");
//	else
//		printf("大端");
//	return 0;
//}
//2. 枚举类型
//2.1 枚举类型的声明
//枚举顾名思义就是⼀ 列举。
//把可能的取值⼀ 列举。
//⽐如我们现实⽣活中：
//⼀周的星期⼀到星期⽇是有限的7天，可以⼀ 列举
//性别有：男、⼥、保密，也可以⼀ 列举
//⽉份有12个⽉，也可以⼀ 列举
//三原⾊，也是可以⼀ 列举
//这些数据的表⽰就可以使⽤枚举了。
//enum day//星期
//{
//	Mon,
//	Tues,
//	Wed,
//	Thur,
//	Fri,
//	Sat,
//    Sun
//};
//enum Color//颜⾊
//{
//	RED,
//	GREEN,
//	BLUE
//};
//int main()
//{
//	printf("%d\n",RED);
//	printf("%d\n", GREEN);
//	printf("%d\n", BLUE);
//	return 0;
//	//输出结果
//	   /* 0 //不可以改
//		1
//		2*/
//}
// enum Color//颜⾊
//{
//	RED=99,
//	GREEN,
//	BLUE
//};
//int main()
//{
//	printf("%d\n",RED);
//	printf("%d\n", GREEN);
//	printf("%d\n", BLUE);
//	return 0;
//	//输出结果
//	   /* 99
//		100
//		101*/
//}

//以上定义的 enum Day ， enum Sex ， enum Color 都是枚举类型。
////{
//}中的内容是枚举类型的可能取值，也叫 枚举常量 。
//这些可能取值都是有值的，默认从0开始，依次递增1，当然在声明枚举类型的时候也可以赋初值。
//enum Color//颜⾊
//{
//	RED = 2,
//	GREEN = 4,
//	BLUE = 8
//};
//2.2 枚举类型的优点
//为什么使⽤枚举？
//我们可以使⽤ #define 定义常量，为什么⾮要使⽤枚举？
//枚举的优点：
//1. 增加代码的可读性和可维护性
//2. 和#define定义的标识符⽐较枚举有类型检查，更加严谨。
//3. 便于调试，预处理阶段会删除 #define 定义的符号
//4. 使⽤⽅便，⼀次可以定义多个常量
//5. 枚举常量是遵循作⽤域规则的，枚举声明在函数内，只能在函数内使⽤
//2.3 枚举类型的使⽤
 enum Color//颜⾊
{
	RED,
	GREEN,
	BLUE
};
 int main()
 {
	 enum Color s = BLUE;
	 if (s == BLUE)
		 printf("蓝色\n");
	 else if (s == RED)
	 printf("红色\n");
	 else
	 {
		 printf("绿色\n");
	 }
	 return 0;
 }
 enum Color//颜⾊
 {
	 RED = 1,
	 GREEN = 2,
	 BLUE = 4
 };
 enum Color clr = GREEN;//使⽤枚举常量给枚举变量赋值 
 那是否可以拿整数给枚举变量赋值呢？在C语⾔中是可以的，但是在C++是不⾏的，C++的类型检查⽐
	 较严格。